#include "threadPool.h"
extern toml_table_t *conf;

int conf_init(toml_table_t **conf) {
  FILE *fp;
  char errbuf[200];
  fp = fopen("../conf.toml", "r");
  if (!fp) {
    fprintf(stderr, "cannot open sample.toml - %s", strerror(errno));
    return -1;
  }
  *conf = toml_parse_file(fp, errbuf, sizeof(errbuf));
  fclose(fp);
  if (!conf) {
    fprintf(stderr, "cannot parse - %s", errbuf);
    return -1;
  }
  return 0;
}

int conf_server(server_configure *s) {

  toml_table_t *server = toml_table_in(conf, "Server");
  if (!server) {
    fprintf(stderr, "missing [server].\n");
    return -1;
  }
  toml_datum_t host = toml_string_in(server, "host");
  if (!host.ok) {
    fprintf(stderr, "cannot read server.host.\n");
    return -1;
  }
  toml_datum_t port = toml_string_in(server, "port");
  if (!port.ok) {
    fprintf(stderr, "cannot read server.port.\n");
    return -1;
  }
   toml_datum_t port2 = toml_string_in(server, "port2");
  if (!port2.ok) {
    fprintf(stderr, "cannot read server.port2.\n");
    return -1;
  }
  toml_datum_t work_num = toml_int_in(server, "work_num");
  if (!work_num.ok) {
    fprintf(stderr, "cannot read server.work_num.\n");
    return -1;
  }
  strcpy(s->host, host.u.s);
  strcpy(s->port, port.u.s);
  strcpy(s->port2, port2.u.s);
  s->work_num = work_num.u.i;

  free(host.u.s);
  free(port.u.s);
  free(port2.u.s);

  return 0;
}

int conf_mysql(sql_config *s) {

  toml_table_t *mysql = toml_table_in(conf, "Mysql");
  if (!mysql) {
    fprintf(stderr, "missing [Mysql].\n");
    return -1;
  }
  toml_datum_t host = toml_string_in(mysql, "host");
  if (!host.ok) {
    fprintf(stderr, "cannot read mysql.host.\n");
    return -1;
  }
  toml_datum_t user_name = toml_string_in(mysql, "user_name");
  if (!user_name.ok) {
    fprintf(stderr, "cannot read mysql.user_name.\n");
    return -1;
  }

  toml_datum_t pass_word = toml_string_in(mysql, "pass_word");
  if (!pass_word.ok) {
    fprintf(stderr, "cannot read mysql.pass_word.\n");
    return -1;
  }

  toml_datum_t data_base = toml_string_in(mysql, "data_base");
  if (!data_base.ok) {
    fprintf(stderr, "cannot read mysql.data_base.\n");
    return -1;
  }

  toml_datum_t port = toml_int_in(mysql, "port");
  if (!port.ok) {
    fprintf(stderr, "cannot read mysql.port.\n");
    return -1;
  }
  strcpy(s->host, host.u.s);
  strcpy(s->user_name, user_name.u.s);
  strcpy(s->pass_word, pass_word.u.s);
  strcpy(s->data_base, data_base.u.s);
  s->port = port.u.i;

  free(host.u.s);
  free(user_name.u.s);
  free(pass_word.u.s);
  free(data_base.u.s);
  return 0;
}

char *get_hash(const char *filename, const char *algorithm) {
  int fd = open(filename, O_RDONLY);
  if (fd < 0) {
    perror("打开文件失败");
    return NULL;
  }

  EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
  if (mdctx == NULL) {
    fprintf(stderr, "EVP_MD_CTX_new 创建失败\n");
    close(fd);
    return NULL;
  }

  /* 使用 EVP_MD_fetch 获取指定的哈希算法 */
  EVP_MD *md = EVP_MD_fetch(NULL, algorithm, NULL);
  if (md == NULL) {
    fprintf(stderr, "EVP_MD_fetch 获取算法失败: %s\n", algorithm);
    EVP_MD_CTX_free(mdctx);
    close(fd);
    return NULL;
  }

  if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) {
    fprintf(stderr, "EVP_DigestInit_ex 初始化失败\n");
    EVP_MD_free(md);
    EVP_MD_CTX_free(mdctx);
    close(fd);
    return NULL;
  }

  unsigned char buffer[4096];
  ssize_t bytes_read;
  while ((bytes_read = read(fd, buffer, sizeof(buffer))) > 0) {
    if (EVP_DigestUpdate(mdctx, buffer, bytes_read) != 1) {
      fprintf(stderr, "EVP_DigestUpdate 处理数据失败\n");
      EVP_MD_free(md);
      EVP_MD_CTX_free(mdctx);
      close(fd);
      return NULL;
    }
  }
  if (bytes_read < 0) {
    perror("读取文件失败");
    EVP_MD_free(md);
    EVP_MD_CTX_free(mdctx);
    close(fd);
    return NULL;
  }
  close(fd);

  unsigned int digest_len = 0;
  unsigned char *digest = OPENSSL_malloc(EVP_MD_size(md));
  if (digest == NULL) {
    fprintf(stderr, "内存分配失败\n");
    EVP_MD_free(md);
    EVP_MD_CTX_free(mdctx);
    return NULL;
  }
  if (EVP_DigestFinal_ex(mdctx, digest, &digest_len) != 1) {
    fprintf(stderr, "EVP_DigestFinal_ex 计算哈希失败\n");
    OPENSSL_free(digest);
    EVP_MD_free(md);
    EVP_MD_CTX_free(mdctx);
    return NULL;
  }

  EVP_MD_free(md);
  EVP_MD_CTX_free(mdctx);

  /* 将二进制哈希转换为16进制字符串 */
  char *hash_hex = malloc(digest_len * 2 + 1);
  if (hash_hex == NULL) {
    OPENSSL_free(digest);
    return NULL;
  }
  for (unsigned int i = 0; i < digest_len; i++) {
    sprintf(&hash_hex[i * 2], "%02x", digest[i]);
  }
  hash_hex[digest_len * 2] = '\0';
  OPENSSL_free(digest);
  return hash_hex;
}

int verify_hash(const char *filename, const char *algorithm,
                const char *expected_hash) {
  char *computed_hash_hex = get_hash(filename, algorithm);
  if (computed_hash_hex == NULL) {
    return -1;
  }
  int result = (strcasecmp(computed_hash_hex, expected_hash) == 0) ? 1 : 0;
  free(computed_hash_hex);
  return result;
}

int deal_stack(char *str, stack *s) {
  if (strlen(str) == 0) {
    return -1;
  }
  if (strcmp(str, "..") == 0) {
    stack_pop(s);
  } else if (strcmp(str, ".") == 0) {
  } else {
    stack_push(s, str);
  }
  return 0;
}

int deal_path(char *path, char *ret_path) {

  stack *s = stack_init();
  char *token;
  token = strtok(path, "/\n");
  if (!token) {
    return -1;
  }

  deal_stack(token, s);
  while ((token = strtok(NULL, "/\n")) != NULL) {
    deal_stack(token, s);
  }

  char res[4096] = "/";
  for (int i = 0; i <= s->top; i++) {
    strcat(res, s->data[i]);
    if (i < s->top)
      strcat(res, "/");
  }
  strcpy(ret_path, res);
  stack_destory(s);
  return 0;
}

int path_exist(char *path) { return access(path, F_OK) == 0; }

int is_file(char *path) {
  struct stat info;
  stat(path, &info);
  if (!S_ISREG(info.st_mode)) {
    return -1;
  }
  return 0;
}

int is_dir(char *path) {
  struct stat info;
  stat(path, &info);
  if (!S_ISDIR(info.st_mode)) {

    return -1;
  }
  return 0;
}

int recursive_mkdir(char *path, mode_t mode) {
  struct stat sb;
  if (stat(path, &sb) == 0) {
    if (S_ISDIR(sb.st_mode)) {
      return 0;
    }
    return -1;
  }
  char parent[4096] = {0};
  strcpy(parent, path);

  char *p = strrchr(parent, '/');
  if (p) {
    *p = '\0';
    if (recursive_mkdir(parent, mode) != 0)
      return -1;
  }

  if (mkdir(path, 0777) != 0) {
    return -1;
  }
  return 0;
}

char random_char() {
  int x = rand() % 66;
  return "abcdefghijklmnopqrstuvwxyz.+-1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"[x];
}

void random_salt(char *slat_c) {
  char salt[15] = {0};
  int x = rand() % 10;
  sprintf(salt, "$%d$", x);
  for (int i = 3; i <= 10; i++) {
    salt[i] = random_char();
  }
  salt[11] = '$';
  // printf("salt: %s\n", salt);
  strcpy(slat_c, salt);
}

char* strftime_local() {
    static char buffer[20];
    time_t now = time(NULL);
    struct tm *tm_info = localtime(&now);
    strftime(buffer, 20, "%Y-%m-%d %H:%M:%S", tm_info);
    return buffer;
}